Skip to content

fix(osx): make ofAVFoundationPlayer::close() synchronous and single-shot - #8527

Open
smeyfroi wants to merge 1 commit into
openframeworks:masterfrom
smeyfroi:fix/ofavfoundationplayer-close-async-teardown
Open

fix(osx): make ofAVFoundationPlayer::close() synchronous and single-shot#8527
smeyfroi wants to merge 1 commit into
openframeworks:masterfrom
smeyfroi:fix/ofavfoundationplayer-close-async-teardown

Conversation

@smeyfroi

Copy link
Copy Markdown
Contributor

Problem

Intermittent crash on application exit, reported on an AVFoundation internal queue (com.apple.coremedia.player.async.<addr>.P/GT), whenever the app quits while a video is loaded. Reproduced on macOS 26 / Apple silicon; the crash is timing-dependent and hits perhaps one exit in five under a playing video.

Cause

Two independent asynchronous teardowns of the same player object were in flight, and neither was waited for:

  1. close() called -close, which is unloadVideoAsync. That nils _player, _playerItem, _videoOutput and _asset on the calling thread but defers cancelReading, cancelPendingSeeks, the KVO and NSNotificationCenter removals, -removeOutput:, -removeTimeObserver: and the CFRelease of the sample buffers to a block on a global concurrent queue. close() returned immediately.
  2. close() also left videoPlayer non-null, so ~ofAVFoundationPlayerdisposePlayer() dispatched a second -unloadVideo of the same object on another queue. Both take asyncLock and both can signal deallocCond.

At exit the process goes on to destroy the GL context and run atexit handlers and static destructors concurrently with those blocks and with the AVPlayer's own serial queue. The player was also never paused, so it was still playing when closed.

Fix

Pause so CoreMedia winds down at rate 0, use the existing blocking -unloadVideo so close() returns only once AVFoundation has finished, and null the handle so disposePlayer() finds nothing to dispatch. No API change; -unloadVideo is already present and is the synchronous sibling of the call being replaced.

Verification

With the patch, repeated quit-during-playback cycles no longer crash; without it the CoreMedia-queue crash reproduces intermittently on exit.

Fixes an intermittent crash on application exit reported on an AVFoundation
internal queue (com.apple.coremedia.player.async.<addr>.P/GT).

Two independent asynchronous teardowns of the same player object were in flight,
and neither was waited for:

1. close() called -close, which is unloadVideoAsync. That nils _player,
   _playerItem, _videoOutput and _asset on the calling thread but defers
   cancelReading, cancelPendingSeeks, the KVO and NSNotificationCenter removals,
   -removeOutput:, -removeTimeObserver: and the CFRelease of the sample buffers
   to a block on a global concurrent queue. close() returned immediately.

2. close() also left videoPlayer non-null, so ~ofAVFoundationPlayer ->
   disposePlayer() dispatched a second -unloadVideo of the same object on another
   queue. Both take asyncLock and both can signal deallocCond.

At exit the process goes on to destroy the GL context and run atexit handlers and
static destructors concurrently with those blocks and with the AVPlayer's own
serial queue. The player was also never paused, so it was still playing when
closed.

Pause so CoreMedia winds down at rate 0, use the existing blocking -unloadVideo
so close() returns only once AVFoundation has finished, and null the handle so
disposePlayer() finds nothing to dispatch. No API change; -unloadVideo is already
present and is the synchronous sibling of the call being replaced.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant